using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using TALoaders;

namespace TALoaders.Tests
{
    using NUnit.Framework;

    [TestFixture]
    class TestCachedDownloader
    {
        [Test]
        [Category("DataCollection")]
        public void getHistoricalData()
        {
            CachedDownloader.clearCache();
            string ticker = "NYSE:JPM";
            QuoteType type = QuoteType.Close;
            CachedDownloader cLoader = new CachedDownloader(new GoogleDownloader());

            SortedList<DateTime, double> prices1;
            Assert.AreEqual(0, cLoader.getCacheSize(), "Cache should be empty");

            // First load (from Google)
            DateTime startDate = new DateTime(2010, 6, 1);
            DateTime endDate = new DateTime(2010, 6, 4);
            Stopwatch stopWatch = new Stopwatch();

            stopWatch.Start();
            prices1 = cLoader.getHistoricalPrices(ticker, startDate, endDate, type);
            stopWatch.Stop();
            long loadTime1 = stopWatch.ElapsedMilliseconds;

            // Check that the cache is created
            Assert.AreEqual(4, prices1.Count, "Prices from Google"); // todo: strange, downloades data up to 8th...
            Assert.AreEqual(4, cLoader.getCacheSize(), "Cache should be filled now");

            // Next load (now should be from Cache)
            stopWatch.Reset();
            stopWatch.Start();
            SortedList<DateTime, double> prices3 = cLoader.getHistoricalPrices(ticker, startDate, endDate, type);
            stopWatch.Stop();
            long loadTime3 = stopWatch.ElapsedMilliseconds;
            Assert.AreEqual(prices1, prices3, "Comparing the second download to the first");
            Assert.Greater(loadTime1, loadTime3 * 4, "Comparing time needed to retrieve downloaded and cached values");

            // Next load, partially from cache and partially from Google
            startDate = new DateTime(2010, 5, 20);
            stopWatch.Reset();
            stopWatch.Start();
            SortedList<DateTime, double> prices4 = cLoader.getHistoricalPrices(ticker, startDate, endDate, type);
            stopWatch.Stop();
            long loadTime4 = stopWatch.ElapsedMilliseconds;
            Assert.AreEqual(38.62, prices4[new DateTime(2010, 5, 24)], "New downloaded values");
            Assert.Greater(loadTime1, loadTime4, "Should be faster to download just updates");
            Assert.Greater(loadTime4, loadTime3, "Should be faster to go only from cache");

            // New loader should have access to the cache from the first loader
            CachedDownloader cLoader2 = new CachedDownloader(new GoogleDownloader());
            stopWatch.Reset();
            stopWatch.Start();
            SortedList<DateTime, double> prices5 = cLoader2.getHistoricalPrices(ticker, startDate, endDate, type);
            stopWatch.Stop();
            long loadTime5 = stopWatch.ElapsedMilliseconds;
            Assert.AreEqual(prices4, prices5, "Same results as from previous loader");
            Assert.Greater(loadTime4, loadTime5, "Should be faster just form cache");
        }

        [Test]
        [Category("Calculation")]
        public void cacheSerialization()
        {
            CachedDownloader.clearCache();
            CachedDownloader loader = new CachedDownloader(new TestDownloader());

            string referenceCacheFile = "..\\..\\Tests\\TestCache.cache";
            string tmpFileName = "test-delete-me.cache";
            string ticker = "SEB";
            QuoteType type = QuoteType.Close;
            DateTime startDate = new DateTime(2010, 7, 16);
            DateTime endDate = new DateTime(2010, 7, 21);

            SortedList<DateTime, double> prices;
            // check that the cash is empty
            Assert.AreEqual(0, loader.getCacheSize(), "Cache should be empty now");
            prices = loader.getHistoricalPrices(ticker, startDate, endDate, type);
            SortedList<DateTime, double> prices1 = new SortedList<DateTime, double>(prices);
            
            Assert.Greater(loader.getCacheSize(), 0, "Cache should be filled now");
            CachedDownloader.saveCacheToFile(tmpFileName);
            FileAssert.AreEqual(referenceCacheFile, tmpFileName);

            CachedDownloader.clearCache();
            prices.Clear();
            Assert.AreNotEqual(prices1, prices, "Prices are cleared and prices1 still contain data");

            Assert.AreEqual(0, loader.getCacheSize(), "Cache should be empty AGAIN");
            CachedDownloader.openCacheFromFile(tmpFileName);
            Assert.Greater(loader.getCacheSize(), 0, "Cache should be filled AGAIN");

            //System.IO.File.Delete(tmpFileName); // clean up
        }

        [Test]
        [Category("Calculation")]
        public void cacheModification()
        {
            CachedDownloader.clearCache();
            CachedDownloader loader = new CachedDownloader(new TestDownloader());

            string ticker = "SRM";
            QuoteType type = QuoteType.Close;
            DateTime startDate = new DateTime(2010, 7, 13);
            DateTime endDate = new DateTime(2010, 7, 15);


            // check that the cash is empty
            Assert.AreEqual(0, loader.getCacheSize(), "Cache should be empty now");
            SortedList<DateTime, double> prices = loader.getHistoricalPrices(ticker, startDate, endDate, type);
            Assert.AreEqual(3, prices.Count, "1: Size of return price array");

            Assert.AreEqual(3, loader.getCacheSize(), "2: Size of cache");

            startDate = startDate.AddDays(-1);  // extra date
            endDate = endDate.AddDays(+1);
            SortedList<DateTime, double> prices1 = loader.getHistoricalPrices(ticker, startDate, endDate, type);
            Assert.AreEqual(5, loader.getCacheSize(), "Size of cache should have expanded");
         }

        [Test]
        [Category("Calculation")]
        public void prevNextWeekDay()
        {
            DateTime wednesday = new DateTime(2010, 6, 16);
            DateTime friday = new DateTime(2010, 6, 18);
            DateTime saturday = new DateTime(2010, 6, 19);
            DateTime sunday = new DateTime(2010, 6, 20);
            DateTime monday = new DateTime(2010, 6, 21);
            Assert.AreEqual(wednesday, Utilities.thisOrNextWeekDay(wednesday), "thisOrNext: Wednesday is week day");
            Assert.AreEqual(wednesday, Utilities.thisOrPrevWeekDay(wednesday), "thisOrPrev: Wednesday is week day");
            Assert.AreEqual(friday, Utilities.thisOrPrevWeekDay(saturday), "Friday is previous working day before Saturday");
            Assert.AreEqual(friday, Utilities.thisOrPrevWeekDay(sunday), "Friday is previous working day before Sunday");
            Assert.AreEqual(monday, Utilities.thisOrNextWeekDay(saturday), "Monday is next working day after Saturday");
            Assert.AreEqual(monday, Utilities.thisOrNextWeekDay(sunday), "Monday is next working day after Sunday");
        }

        [Test]
        [Category("Calculation")]
        public void DownloaderFactoryGetDefaultTickers()
        {
            // TestDownloader
            string[] tickers = DownloaderFactory.getDefaultTickers(Loader.Test.ToString());
            Assert.Greater(tickers.Length, 1, "Default tickers for TEST Downloader");
            
            // Yahoo
            tickers = DownloaderFactory.getDefaultTickers(Loader.Yahoo.ToString());
            List<string> lTickers = new List<string>(tickers);
            Assert.Contains("^OMX", lTickers, "^OMX in default tickers for Yahoo");
            Assert.Contains("^GDAXI", lTickers, "^GDAXI in deault tickers for Yahoo");

            // Google
            lTickers = new List<string>(DownloaderFactory.getDefaultTickers(Loader.Google.ToString()));
            Assert.Contains("OIL", lTickers, "OIL in default tickers for Google");

            // Oanda
            lTickers = new List<string>(DownloaderFactory.getDefaultTickers(Loader.OandaFX.ToString()));
            Assert.Contains("EURUSD", lTickers, "EURUSD in default tickers for Oanda");

            // Bloomberg
            lTickers = new List<string>(DownloaderFactory.getDefaultTickers(Loader.Bloomberg.ToString()));
            Assert.Contains("OMX Index", lTickers, "OMX Index in default tickers for Bloomberg");
        }
    }
}
